﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Windows;
using System.Windows.Threading;
using Microsoft.VisualStudio.ExtensionsExplorer;
using Microsoft.VisualStudio.ExtensionsExplorer.UI;
using VsxFactory.Modeling.Repository;
using VsxFactory.Modeling.StrategyManager.Strategies;

namespace VsxFactory.Modeling.StrategyManager.Dialog.Providers
{
    /// <summary>
    /// IVsExtensionsProvider implementation responsible for gathering
    /// a list of packages from a package feed which will be shown in the Add NuGet dialog.
    /// </summary>
    internal class OnlineProvider : PackagesProviderBase
    {
        private IPackageSourceProvider _packageSourceProvider;

        public OnlineProvider(IPackageSourceProvider packageSourceProvider, VisualStudioStrategyContext context, ResourceDictionary resources)
            : base(context, resources) {
            _packageSourceProvider = packageSourceProvider;
        }

        public override float SortOrder {
            get {
                return 2.0f;
            }
        }

        public override string Name {
            get {
                return "Online";
            }
        }

        public override bool RefreshOnNodeSelection {
            get {
                // only refresh if the current node doesn't have any extensions
                return (SelectedNode == null || SelectedNode.Extensions.Count == 0);
            }
        }

        [System.Diagnostics.CodeAnalysis.SuppressMessage(
            "Microsoft.Design",
            "CA1031:DoNotCatchGeneralExceptionTypes",
            Justification = "We want to suppress all errors to show an empty node.")]
        protected override void FillRootNodes() {
            var packageSources = _packageSourceProvider.GetPackageSources();

            // create one tree node per package source
            // REVIEW: do we want to truncate the number of nodes?
            foreach (var source in packageSources) {
                PackagesTreeNodeBase node = null;
                try {
                    IPackageRepository repository = new OnlinePackageRepository(Context, source);
                    node = new SimpleTreeNode(this, source.Name, RootNode, repository);

                    // pre-select the active package source by default
                    if (source.Equals(_packageSourceProvider.ActivePackageSource)) {
                        SelectNode(node);
                    }
                }
                catch (Exception) {
                    // exception occurs if the Source value is invalid. In which case, adds an empty tree node in place.
                    node = new EmptyTreeNode(this, source.Name, RootNode);
                }

                RootNode.Nodes.Add(node);
            }
        }

        protected override bool ExecuteCore(PackageItem item) {
            // display license window if necessary
            //if (item.RequireLicenseAcceptance)
            //{
            //    bool accepted = licenseWindowOpener.ShowLicenseWindow(item.PackageIdentity);
            //    if (!accepted)
            //    {
            //        return false;
            //    }
            //}

            Context.LocalRepository.InstallPackage(item.PackageIdentity);
            return true;
        }

        protected override void OnExecuteCompleted(PackageItem item) {
            item.UpdateEnabledStatus();
        }

        public override bool CanExecute(PackageItem item) {
            // only enable command on a Package in the Online provider if it is not installed yet
            return !Context.LocalRepository.GetPackages().Any(p => p.ID == item.Id && p.Version == item.Version);
        }

        public override IVsExtension CreateExtension(PackageInfo package) {
            return new PackageItem(this, package, null) {
                CommandName = "Install"
            };
        }

        public override string NoItemsMessage {
            get {
                return Resources.Dialog_OnlineProviderNoItem;
            }
        }

        public override string ProgressWindowTitle {
            get {
                return Resources.Dialog_InstallProgress;
            }
        }

        protected override string GetProgressMessage(PackageInfo package) {
            return Resources.Dialog_InstallProgress + package.ToString();
        }
    }

}